#ifndef __BLOCK_QUEUE_HPP__
#define __BLOCK_QUEUE_HPP__
#include <iostream>
#include <pthread.h>
#include <queue>
template <typename T>
class BlockQueue
{
public:
    bool is_full()
    {
        return _BlockQueue.size() == _cap;
    }
    bool is_empty()
    {
        return _BlockQueue.empty();
    }

public:
    BlockQueue(int cap)
        : _cap(cap)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_productor_cond, nullptr);
        pthread_cond_init(&_consumer_cond, nullptr);
        productor_wait_num = 0;
        consumer_wait_num = 0;
    }
    void enqueue(T &in) // 生产者使用接口
    {
        pthread_mutex_lock(&_mutex);
        while(is_full())//防止多个线程被唤醒，只有一个位置需要生产，出现bug，每个线程被唤醒后要重新判断是否有位置生产数据
        {
            productor_wait_num++;
            pthread_cond_wait(&_productor_cond, &_mutex); // 如果满了，生产者入等待队列，解锁--唤醒--出等待队列，锁定
            productor_wait_num--;
        }
        _BlockQueue.push(in);
        // 通知消费者来买
        // std::cout << "通知消费者来买" << std::endl;
        if(consumer_wait_num > 0)
            pthread_cond_signal(&_consumer_cond);
        // std::cout << "通知完成" << std::endl;

        pthread_mutex_unlock(&_mutex);
    }
    void pop(T *out)//消费者使用的接口
    {
        pthread_mutex_lock(&_mutex);
        while(is_empty())
        {
            // std::cout << "消费者入等待队列" << std::endl;
            consumer_wait_num++;
            pthread_cond_wait(&_consumer_cond, &_mutex); // 如果空了，消费者入等待队列，解锁，---被唤醒--出等待队列，锁定
            consumer_wait_num--;
        }
        *out = _BlockQueue.front();
        _BlockQueue.pop();
        // 通知生产者来卖
        if(productor_wait_num > 0)
            pthread_cond_signal(&_productor_cond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_productor_cond);
        pthread_cond_destroy(&_consumer_cond);
    }

private:
    std::queue<T> _BlockQueue;
    int _cap; // 阻塞队列上限
    pthread_mutex_t _mutex;
    pthread_cond_t _productor_cond; // 生产者等待队列
    pthread_cond_t _consumer_cond;  // 消费者等待队列
    int productor_wait_num;
    int consumer_wait_num;
};
#endif